package cn.luoxiaolong.android.picker.file.utils

import android.content.Context
import android.os.Environment
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import cn.luoxiaolong.android.picker.file.R
import cn.luoxiaolong.android.picker.file.bean.BeanSubscriber
import cn.luoxiaolong.android.picker.file.bean.FileItemBeanImpl
import cn.luoxiaolong.android.picker.file.bean.FileNavBeanImpl
import cn.luoxiaolong.android.picker.file.config.FilePickerConfig.Companion.STORAGE_CUSTOM_ROOT_PATH
import cn.luoxiaolong.android.picker.file.config.FilePickerConfig.Companion.STORAGE_EXTERNAL_STORAGE
import cn.luoxiaolong.android.picker.file.config.FilePickerManager
import java.io.File
import java.io.FileFilter
import java.text.DecimalFormat
import java.text.SimpleDateFormat
import java.util.*
import kotlin.collections.ArrayList

class FileUtils {
    companion object {
        /**
         * 根据配置参数获取根目录文件
         * @return File
         */
        suspend fun suspendGetRootFile() = withContext(Dispatchers.IO) {
            getRootFile()
        }

        fun getRootFile(): File {
            return when (FilePickerManager.config?.mediaStorageType) {
                STORAGE_EXTERNAL_STORAGE -> {
                    File(Environment.getExternalStorageDirectory().absoluteFile.toURI())
                }
                STORAGE_CUSTOM_ROOT_PATH -> {
                    if (FilePickerManager.config?.customRootPath.isNullOrEmpty()) {
                        File(Environment.getExternalStorageDirectory().absoluteFile.toURI())
                    } else {
                        File(FilePickerManager.config?.customRootPath)
                    }
                }
                else -> {
                    File(Environment.getExternalStorageDirectory().absoluteFile.toURI())
                }
            }
        }

        /**
         * 获取给定文件对象[rootFile]下的所有文件，生成列表项对象
         */
        suspend fun suspendProduceListDataSource(rootFile: File, beanSubscriber: BeanSubscriber) =
            withContext(Dispatchers.IO) {
                produceListDataSource(
                    rootFile,
                    beanSubscriber
                )
            }

        fun produceListDataSource(rootFile: File, beanSubscriber: BeanSubscriber): ArrayList<FileItemBeanImpl> {
            var listData: ArrayList<FileItemBeanImpl> = ArrayList()
            if (rootFile.isFile) {
                return listData
            }
            var formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
            val child: Array<File>
            if (FilePickerManager.config?.isShowHiddenFiles ?: false) {
                child = rootFile.listFiles()
            } else {
                child = rootFile.listFiles(FileFilter {
                    !it.isHidden
                })
            }
            for (file in child) {
                val itemBean = FileItemBeanImpl(
                    file.name,
                    file.path,
                    "",
                    "",
                    false,
                    null,
                    file.isDirectory,
                    file.isHidden,
                    beanSubscriber
                )
                if (file.isFile) {
                    val time = formatter.format(Date(file.lastModified()))
                    val size =
                        formatFileSize(file.length());
                    itemBean.fileTime = time
                    itemBean.fileSize = size
                    // 如果调用者没有实现文件类型甄别器，则使用的默认甄别器
                    FilePickerManager.config?.selfFileType?.fillFileType(itemBean)
                        ?: FilePickerManager.config?.defaultFileType?.fillFileType(itemBean)
                }
                listData.add(itemBean)
            }
            listData.run {
                // 隐藏文件处理
                // this.hideFiles<FileItemBeanImpl>(!(FilePickerManager.config?.isShowHiddenFiles ?: false))
                // 排序
                this.sortWith(compareBy({ !it.isDir }, { it.fileName }))
            }
            // 将当前列表数据暴露，以供调用者自己处理数据
            return FilePickerManager.config?.selfFilter?.doFilter(listData) ?: listData
        }

        /**
         * 为导航栏添加数据，也就是每进入一个文件夹，导航栏的列表就添加一个对象
         * 如果是退回到上层文件夹，则删除后续子目录元素
         */
        fun produceNavDataSource(
            currentDataSource: ArrayList<FileNavBeanImpl>,
            nextPath: String,
            context: Context
        ): ArrayList<FileNavBeanImpl> {

            if (currentDataSource.isEmpty()) {
                // 优先级：目标设备名称 --> 自定义路径 --> 默认 SD 卡
                currentDataSource.add(
                    FileNavBeanImpl(
                        if (!FilePickerManager.config?.mediaStorageName.isNullOrEmpty()) {
                            FilePickerManager.config?.mediaStorageName!!
                        } else if (!FilePickerManager.config?.customRootPath.isNullOrEmpty()) {
                            FilePickerManager.config?.customRootPath!!
                        } else {
                            context.getString(R.string.file_picker_tv_sd_card)
                        },
                        nextPath
                    )
                )
                return currentDataSource
            }

            for (data in currentDataSource) {
                // 如果是回到根目录
                if (nextPath == currentDataSource.first().filePath) {
                    return ArrayList(currentDataSource.subList(0, 1))
                }
                // 如果是回到当前目录（不包含根目录情况）
                // 直接返回
                val isCurrent = nextPath == currentDataSource[currentDataSource.size - 1].filePath
                if (isCurrent) {
                    return currentDataSource
                }

                // 如果是回到上层的某一目录(即，当前列表中有该路径)
                // 将列表截取至目标路径元素
                val isBackToAbove = nextPath == data.filePath
                if (isBackToAbove) {
                    return ArrayList(currentDataSource.subList(0, currentDataSource.indexOf(data) + 1))
                }
            }
            // 循环到此，意味着将是进入子目录
            currentDataSource.add(
                FileNavBeanImpl(
                    nextPath.substring(nextPath.lastIndexOf("/") + 1),
                    nextPath
                )
            )
            return currentDataSource
        }

        /**
         * 格式化文件大小，根据文件大小不同使用不同单位
         *
         * @param size   文件大小
         * @param format 数字的格式
         * @return 字符串形式的大小，包含单位(B,KB,MB,GB,TB,PB)
         */
        fun formatFileSize(size: Long): String {
            var format = DecimalFormat("#.00")
            return if (size < 1024) {
                "$size B"
            } else if (size < 1048576) {
                format.format(size / 1024.00) + " KB"
            } else if (size < 1073741824) {
                format.format(size / 1048576.00) + " MB"
            } else if (size < 1099511627776L) {
                format.format(size / 1073741824.00) + " GB"
            } else if (size < 1125899906842624L) {
                format.format(size / 1099511627776.00) + " TB"
            } else if (size < 1152921504606846976L) {
                format.format(size / 1125899906842624.00) + " PB"
            } else {
                "?.?? ??"
            }
        }
    }
}

private fun <E> java.util.ArrayList<FileItemBeanImpl>?.hideFiles(hide: Boolean) {
    if (hide) {
        this?.removeAll { it.isHide }
    }
}
